package cn.edu.cug.cs.gtl.docsrv.shp.dao.impl;

import cn.edu.cug.cs.gtl.common.Pair;
import cn.edu.cug.cs.gtl.docsrv.Managers;
import cn.edu.cug.cs.gtl.docsrv.config.Configuration;
import cn.edu.cug.cs.gtl.docsrv.config.FTPConfig;
import cn.edu.cug.cs.gtl.docsrv.config.HDFSConfig;
import cn.edu.cug.cs.gtl.docsrv.shp.block.ShapeBlock;
import cn.edu.cug.cs.gtl.docsrv.shp.catalog.CatalogTree;
import cn.edu.cug.cs.gtl.docsrv.shp.querier.BlockQuerier;
import cn.edu.cug.cs.gtl.docsrv.shp.manager.FTPShpManager;
import cn.edu.cug.cs.gtl.docsrv.shp.manager.RDBShpManager;
import cn.edu.cug.cs.gtl.docsrv.shp.dao.ShpDao;
import cn.edu.cug.cs.gtl.docsrv.shp.querier.FeatureQuerier;
import cn.edu.cug.cs.gtl.docsrv.shp.querier.GeometryQuerier;
import cn.edu.cug.cs.gtl.docsrv.shp.updater.BlockUpdater;
import cn.edu.cug.cs.gtl.mybatis.Session;
import cn.edu.cug.cs.gtl.mybatis.mapper.shp.*;
import cn.edu.cug.cs.gtl.mybatis.metadata.ShpUtils;
import cn.edu.cug.cs.gtl.net.ftp.client.ClientFTP;
import cn.edu.cug.cs.gtl.docsrv.shp.manager.HDFSShpManager;
import cn.edu.cug.cs.gtl.docsrv.shp.manager.ShpManager;
import cn.edu.cug.cs.gtl.net.hdfs.client.ClientHDFS;
import cn.edu.cug.cs.gtl.protos.Document;
import cn.edu.cug.cs.gtl.protos.Tree;
import cn.edu.cug.cs.gtl.tree.HashTree;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.springframework.stereotype.Component;


import javax.print.Doc;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

@Component
public class ShpDaoImpl implements ShpDao {
    ShpManager shpManager =null;

    public ShpDaoImpl() {
        super();
    }

    /**
     * 服务编号：7001
     * 服务名称：addShp
     * 功能描述：单个本地Shp文件入库
     * 接口描述： /api/shp/addShp
     * 传入参数：
     * ShpAll  shp；前端传入ShpAll的JSON对象
     * 返回值：
     * 成功返回true , 否则返回false
     * 调用示例：
     *
     * @param shpAll
     */
    @Override
    public void addShp(ShpAll shpAll) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        shpManager.insert(shpAll);
    }

    /**
     * 服务编号：7002
     * 服务名称：addShps
     * 功能描述：多个本地SHP文件入库
     * 接口描述： /api/shp/ addShps
     * 传入参数：
     * List<ShpAll>  shps；前端传入ShpAll列表的JSON对象
     * 返回值：
     * 成功返回true , 否则返回false
     * 调用示例：
     *
     * @param ls
     */
    @Override
    public void addShps(List<ShpAll> ls) {
        if(ls==null || ls.size()==0)
            return;
        for(ShpAll shpAll: ls)
            addShp(shpAll);
    }

    /**
     * 服务编号：7003
     * 服务名称：addFromRawDB
     * 功能描述：从原始数据库中提取指定类型的图形文件入库
     * 接口描述： /api/shp/addFromRawDB
     * 传入参数：
     * String shpType   图形类型，文件后缀；
     * 返回值：
     * 成功返回true , 否则返回false
     * 调用示例：
     */
    @Deprecated
    @Override
    public boolean addFromRawDB() {
        return false;
    }

    /**
     * 服务编号：7004
     * 服务名称：getShpByName
     * 功能描述：图形数据库中提取指定名称的图形文件
     * 接口描述： /api/shp/getShpByName
     * 传入参数：
     * String shpName   图形名称；
     * 返回值：
     * List<ShpAll> shpAllList 的JSON字符串
     * 调用示例：
     *
     * @param shpName
     */
    @Override
    public List<ShpAll> getShpByName(String shpName) {
        return getShpByEnTitle(shpName);
    }

    /**
     * 服务编号：7005
     * 服务名称：getShpByEnTitle
     * 功能描述：图形数据库中提取指定英文名称的图形文件
     * 接口描述： /api/shp/ getShpByEnTitle
     * 传入参数：
     * String enTitle ；
     * 返回值：
     * List<ShpAll> shpAllList 的JSON字符串
     * 调用示例：
     *
     * @param enTitle
     */
    @Override
    public List<ShpAll> getShpByEnTitle(String enTitle) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        return shpManager.queryByEnTitle(enTitle);
    }

    /**
     * 服务编号：7006
     * 服务名称：getShpByCnTitle
     * 功能描述：图形数据库中提取指定中文名称的图形文件
     * 接口描述： /api/shp/ getShpByCnTitle
     * 传入参数：
     * String cnTitle ；
     * 返回值：
     * List<ShpAll> shpAllList 的JSON字符串
     * 调用示例：
     *
     * @param cnTitle
     */
    @Override
    public List<ShpAll> getShpByCnTitle(String cnTitle) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        return shpManager.queryByComment(cnTitle);
    }

    /**
     * 服务编号：7007
     * 服务名称：getShpByInternalId
     * 功能描述：图形数据库中提取指定ID的图形文件
     * 接口描述： /api/shp/getShpByInternalId
     * 传入参数：
     * long internalId；
     * 返回值：
     * ShpAll  shp     ; ShpAll的JSON字符串
     * 调用示例：
     *
     * @param internalId
     */
    @Override
    public ShpAll getShpByInternalId(BigDecimal internalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        ShpAll shpAll = shpManager.queryByInternalId(internalId);
        return shpAll;
    }

    /**
     * 服务编号：7008
     * 服务名称：getShpByBoundingBox
     * 功能描述：图形数据库中提取指定范围的图形
     * 接口描述： /api/shp/getShpByBoundingBox
     * 传入参数：
     *      String bb；//minx,maxx,miny,maxy  数字之间逗号分隔
     *      String mask; //intersect 相交的图形； 或  contains 包含的图形
     * 返回值：
     * List<ShpAll> shpAllList 的JSON字符串
     * 调用示例：
     *
     * @param g
     * @param mask
     */
    @Override
    public List<ShpAll> getShpByBoundingBox(Geometry g, String mask) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier bq = shpManager.getBlockQuerier();
        List<ShpAll> shpAllList = new ArrayList<>();
        if("intersect".equals(mask)) {
            if (bq.intersects(g)) {
                Iterator<ShapeBlock> shapeBlockIterator = bq.iterator();
                while (shapeBlockIterator.hasNext())
                    shpAllList.add(shapeBlockIterator.next().getShpAll());
            }
        }
        else{
            if (bq.contains(g)) {
                Iterator<ShapeBlock> shapeBlockIterator = bq.iterator();
                while (shapeBlockIterator.hasNext())
                    shpAllList.add(shapeBlockIterator.next().getShpAll());
            }
        }
        return shpAllList;
    }

    /**
     * 服务编号：7009
     * 服务名称：deleteShpByInternalId
     * 功能描述：删除图形数据库中指定ID的图形
     * 接口描述： /api/shp/deleteShpByInternalId
     * 传入参数：
     * long internalId；
     * 返回值：
     * 成功返回true , 否则返回false
     * 调用示例：
     *
     * @param internalId
     */
    @Override
    public boolean deleteShpByInternalId(BigDecimal internalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        ShpAll shpAll =new ShpAll();
        shpAll.setShpInternalId(internalId);
        return shpManager.delete(shpAll);
    }

    /**
     * 服务编号：7010
     * 服务名称：getFeatureByBoundingBox
     * 功能描述：图形数据库中提取指定范围的要素
     * 接口描述： /api/shp/getFeatureByBoundingBox
     * 传入参数：
     * String bb；//minx,maxx,miny,maxy  数字之间逗号分隔
     * String mask; //intersect 相交的要素； 或  contains 包含的要素
     * 返回值：
     * FeatureJSON的列表
     * 调用示例：
     *
     * @param g
     * @param mask
     */
    @Override
    public List<String> getFeatureByBoundingBox(Geometry g, String mask) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier bq = shpManager.getBlockQuerier();

        List<Feature> allFeatures = new ArrayList<>();
        if("intersect".equals(mask)) {
            if (bq.intersects(g)) {
                Iterator<ShapeBlock> shapeBlockIterator = bq.iterator();
                while (shapeBlockIterator.hasNext()) {
                    FeatureQuerier fq = shapeBlockIterator.next().getFeatureQuerier();
                    List<Feature> lf = fq.intersects(g);
                    if(lf!=null)
                        allFeatures.addAll(lf);
                }
            }
        }
        else{
            if (bq.contains(g)) {
                Iterator<ShapeBlock> shapeBlockIterator = bq.iterator();
                while (shapeBlockIterator.hasNext()) {
                    FeatureQuerier fq = shapeBlockIterator.next().getFeatureQuerier();
                    List<Feature> lf = fq.contains(g);
                    if(lf!=null)
                        allFeatures.addAll(lf);
                }
            }
        }

        List<String> jsons = new ArrayList<>();
        if(allFeatures.size()>0){
            try {
                FeatureJSON featureJSON = new FeatureJSON();
                for(Feature f: allFeatures){
                    SimpleFeature sf =(SimpleFeature)f;
                    if(sf.getFeatureType()!=null) {
                        featureJSON.setFeatureType(sf.getFeatureType());
                    }
                    String s = featureJSON.toString(sf);
                    jsons.add(s);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
        return jsons;
    }

    /**
     * 服务编号：7011
     * 服务名称：getGeometryByBoundingBox
     * 功能描述：图形数据库中提取指定范围的几何对象
     * 接口描述： /api/shp/getGeometryByBoundingBox
     * 传入参数：
     * String bb；//minx,maxx,miny,maxy  数字之间逗号分隔
     * String mask; //intersect 相交的要素； 或  contains 包含的要素
     * 返回值：
     * GeometryJSON的列表
     * 调用示例：
     *
     * @param g
     * @param mask
     */
    @Override
    public List<String> getGeometryByBoundingBox(Geometry g, String mask) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier bq = shpManager.getBlockQuerier();

        List<Feature> allFeatures = new ArrayList<>();
        if("intersect".equals(mask)) {
            if (bq.intersects(g)) {
                Iterator<ShapeBlock> shapeBlockIterator = bq.iterator();
                while (shapeBlockIterator.hasNext()) {
                    FeatureQuerier fq = shapeBlockIterator.next().getFeatureQuerier();
                    List<Feature> lf = fq.intersects(g);
                    if(lf!=null)
                        allFeatures.addAll(lf);
                }
            }
        }
        else{
            if (bq.contains(g)) {
                Iterator<ShapeBlock> shapeBlockIterator = bq.iterator();
                while (shapeBlockIterator.hasNext()) {
                    FeatureQuerier fq = shapeBlockIterator.next().getFeatureQuerier();
                    List<Feature> lf = fq.contains(g);
                    if(lf!=null)
                        allFeatures.addAll(lf);
                }
            }
        }

        List<String> jsons = new ArrayList<>();
        if(allFeatures.size()>0){
            try {
                GeometryJSON geometryJSON = new GeometryJSON();
                for(Feature f: allFeatures){
                    SimpleFeature sf =(SimpleFeature)f;
                    String s = geometryJSON.toString((Geometry)sf.getDefaultGeometry());
                    jsons.add(s);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
        return jsons;
    }

    /**
     * 服务编号：7012
     * 服务名称：getGeometriesByShpInternalId
     * 功能描述：图形数据库中提取指定Shp的几何对象
     * 接口描述： /api/shp/getGeometriesByShpInternalId
     * 传入参数：
     * long shpInternalId
     * 返回值：
     * GeometryJSON的列表
     * 调用示例：
     *
     * @param shpInternalId
     */
    @Override
    public List<String> getGeometriesByShpInternalId(BigDecimal shpInternalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier querier = shpManager.getBlockQuerier();
        querier.selectByInternalId(shpInternalId);
        GeometryQuerier gq = querier.iterator().next().getFeatureQuerier();
        return gq.getGeometryJSONs();
    }

    /**
     * 服务编号：7013
     * 服务名称：getEnvelopeByShpInternalId
     * 功能描述：图形数据库中提取指定范围的几何对象
     * 接口描述： /api/shp/getEnvelopeByShpInternalId
     * 传入参数：
     * long shpInternalId
     * 返回值：
     * Envelope
     * 调用示例：
     *
     * @param shpInternalId
     */
    @Override
    public Envelope getEnvelopeByShpInternalId(BigDecimal shpInternalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier querier = shpManager.getBlockQuerier();
        querier.selectByInternalId(shpInternalId);
        GeometryQuerier gq = querier.iterator().next().getFeatureQuerier();
        return gq.getEnvelope();
    }

    /**
     * 服务编号：7014
     * 服务名称：getShpCatalogs
     * 功能描述：图形数据库中提取所有分类
     * 接口描述： /api/shp/getShpCatalogs
     * 传入参数：
     * 返回值：
     * List<ShpCatalog> catalogs
     * 调用示例：
     */
    @Override
    public List<ShpCatalog> getShpCatalogs() {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        return shpManager.getCatalogs();
    }

    /**
     * 服务编号：7015
     * 服务名称：getGeometriesByShpInternalId
     * 功能描述：图形数据库中提取指定Shp的几何对象
     * 接口描述： /api/shp/getFeaturesByShpInternalId
     * 传入参数：
     * long shpInternalId
     * 返回值：
     * FeatureJSON的列表
     * 调用示例：
     *
     * @param shpInternalId
     */
    @Override
    public List<String> getFeaturesByShpInternalId(BigDecimal shpInternalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier querier = shpManager.getBlockQuerier();
        querier.selectByInternalId(shpInternalId);
        GeometryQuerier gq = querier.iterator().next().getFeatureQuerier();
        return gq.getFeatureJSONs();
    }

    /**
     * 服务编号：7016
     * 服务名称：getDocumentByShpInternalId
     * 功能描述：图形数据库中提取指定Shp文档
     * 接口描述： /api/shp/getDocumentByShpInternalId
     * 传入参数：
     * long shpInternalId
     * 返回值：
     * Document doc;
     * 其中，每个Feature的GeoJSON字符串为Document的一个content；
     * 其他的不为空的字段为该Shp文档的元数据。
     * 调用示例：
     * http://localhost:8090/api/shp/getDocumentByShpInternalId?shpInternalId=3
     *
     * @param shpInternalId
     */
    @Override
    public Document getDocumentByShpInternalId(BigDecimal shpInternalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        BlockQuerier querier = shpManager.getBlockQuerier();
        querier.selectByInternalId(shpInternalId);
        Iterator<ShapeBlock> shapeBlocks = querier.iterator();
        //only one
        if(shapeBlocks.hasNext()) {
            ShapeBlock shapeBlock = shapeBlocks.next();
            Document document = ShpUtils.convert(shapeBlock.getShpAll());
            //fill feature geojson string into contents
            FeatureQuerier featureQuerier = shapeBlock.getFeatureQuerier();
            Document doc = document .toBuilder()
                    .addAllContent(featureQuerier.getFeatureJSONs())
                    .build();
            return doc;
        }
        return null;
    }

    @Override
    public List<ShpAll> getShpByCatalogInternalId(BigDecimal catalogInternalId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        try {
              Map<String,Object> p = new LinkedHashMap<String,Object>();
              p.put("shpCatalog",catalogInternalId);
            List<ShpAll> shpAllList = shpManager.query(p);
            return shpAllList;
          }
          catch (Exception e){
              e.printStackTrace();
          }
        return null;
    }

    /**
     * 将所有的目录整理成一个树后返回
     *
     * @return
     */
    @Override
    public CatalogTree getCatalogTree() {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        return shpManager.getCatalogTree();
    }

    @Override
    public List<BigDecimal> getShpInternalIdsByCatalogInternalId(BigDecimal catalogId) {
        if(shpManager==null)
            shpManager=Managers.getShpManager();
        return shpManager.getShpInternalIdsByCatalogInternalId(catalogId);
    }


//
//
//    @Override
//    public List<ShpItem> getShpData() throws Exception {
//        Session session = Configuration.getSession();
//        ShpItemMapper shpItemMapper = session.getMapper(ShpItemMapper.class);
//        List<ShpItem> shpItems = shpItemMapper.selectAll();
//        return shpItems;
//    }
//
//    @Override
//    public List<ShpAll> getShpDataAll() throws Exception {
//        Session session = Configuration.getSession();
//        ShpAllMapper shpAllMapper = session.getMapper(ShpAllMapper.class);
//        List<ShpAll> shpAllList = shpAllMapper.selectAll();
//        return shpAllList;
//    }
//
//    @Override
//    public List<ShpAll> queryShpData(ShpAll shpAll) throws Exception {
//        List<ShpAll> res = new ArrayList<>();
//        if(shpAll.getShpInternalId() != null){
//            //根据主键查询数据库条目, 这里直接用 rdb，不一定有文件，仅仅需要item
//            Session s = Configuration.getSession();
//            ShpManager shpManager = new RDBShpManager(s);
//            ShpAll shpAll1 = shpManager.queryByInternalId(shpAll.getShpInternalId());
//            res.add(shpAll);
//        }else if(shpAll.getShpEnTitle() != null){
//
//
//        }else if(shpAll.getShpCnTitle() != null){
//
//
//        }else if(shpAll.getShpType() != null){
//
//
//        }else if(shpAll.getShpAppendDate() != null){
//
//        }
//
//        return res;
//    }
//
//    @Override
//    public void addShpData(ShpAll shpAll) throws Exception {
//        ShpManager shpManager = Managers.getShpManager();
//        if(shpManager!=null) shpManager.insert(shpAll);
//
//    }
//
//    @Override
//    public void deleteShpData(ShpAll shpAll) throws Exception {
//        ShpManager shpManager = Managers.getShpManager();
//        if(shpManager!=null) shpManager.delete(shpAll);
//
////        String shpUrl = shpAll.getShpUrl();
////        String storeType = shpUrl.split("/")[0];
////        Session session = Configuration.getSession();
////        //根据docUrl判断文档存储位置，使用相应的文档管理器
////        switch (storeType){
////            case "ftp:":{
////                FTPConfig ftpConfig = Configuration.getFtpConfig();
////                ShpManager shpManager = new FTPShpManager(session, ClientFTP.of(ftpConfig.getFtpIP(),
////                        ftpConfig.getFtpPort(), ftpConfig.getFtpUser(),ftpConfig.getFtpPassword(),
////                        ftpConfig.getFtpWorkingDirectory(),ftpConfig.getFtpType()));
////                shpManager.delete(shpAll);
////            }break;
////            case "hdfs:":{
////                ShpManager shpManager = new HDFSShpManager(session);
////                shpManager.delete(shpAll);
////            }break;
////            default:{
////                ShpManager shpManager = new RDBShpManager(session);
////                shpManager.delete(shpAll);
////            }
////        }
//    }
//
//    @Override
//    public void updateShpData(ShpAll shpAll) throws Exception {
//        ShpManager shpManager = Managers.getShpManager();
//        if(shpManager!=null) shpManager.update(shpAll);
//
////        String shpUrl = shpAll.getShpUrl();
////        String storeType = shpUrl.split("/")[0];
////        Session session = Configuration.getSession();
////        //根据docUrl判断文档存储位置，使用相应的文档管理器
////        switch (storeType){
////            case "ftp:":{
////                FTPConfig ftpConfig = Configuration.getFtpConfig();
////                ShpManager shpManager = new FTPShpManager(session, ClientFTP.of(ftpConfig.getFtpIP(),
////                        ftpConfig.getFtpPort(), ftpConfig.getFtpUser(),ftpConfig.getFtpPassword(),
////                        ftpConfig.getFtpWorkingDirectory(),ftpConfig.getFtpType()));
////                shpManager.update(shpAll);
////            }break;
////            case "hdfs:":{
////                ShpManager shpManager = new HDFSShpManager(session);
////                shpManager.delete(shpAll);
////            }break;
////            default:{
////                ShpManager shpManager = new RDBShpManager(session);
////                shpManager.update(shpAll);
////            }
////        }
//    }
//
//    @Override
//    public InputStream downloadShpFile(BigDecimal shpInternalId) throws Exception {
//        ShpManager shpManager = Managers.getShpManager();
//        if(shpManager!=null) {
//            ShpAll shpAll = shpManager.queryByInternalId(shpInternalId);
//            InputStream inputStream = new ByteArrayInputStream(shpAll.getShpRawBytes());
//            return inputStream;
//        }
//        return null;
////
////        Session session = Configuration.getSession();
////        ShpItemMapper shpItemMapper = session.getMapper(ShpItemMapper.class);
////        ShpItem shpItem = shpItemMapper.selectByPrimaryKey(shpInternalId);
////        String shpUrl = shpItem.getShpUrl();
////        String storeType = shpUrl.split("/")[0];
////        byte[] bytes = null;
////        switch (storeType){
////            case "ftp:":{
////                FTPConfig ftpConfig = Configuration.getFtpConfig();
////                ShpManager shpManager = new FTPShpManager(session, ClientFTP.of(ftpConfig.getFtpIP(),
////                        ftpConfig.getFtpPort(), ftpConfig.getFtpUser(),ftpConfig.getFtpPassword(),
////                        ftpConfig.getFtpWorkingDirectory(),ftpConfig.getFtpType()));
////                ShpAll shpAll = shpManager.queryByInternalId(shpInternalId);
////                bytes = shpAll.getShpRawBytes();
////            }break;
////            case "hdfs:":{
////                ShpManager shpManager = new HDFSShpManager(session);
////                ShpAll shpAll = shpManager.queryByInternalId(shpInternalId);
////                bytes = shpAll.getShpRawBytes();
////            }break;
////            default:{
////                ShpFileMapper shpFileMapper = session.getMapper(ShpFileMapper.class);
////                ShpFile shpFile = shpFileMapper.selectByPrimaryKey(shpInternalId);
////                bytes = shpFile.getShpRawBytes();
////            }
////        }
////        InputStream inputStream = new ByteArrayInputStream(bytes);
////        return inputStream;
//    }
}

